/****************************************************************
 ** Product  :   HP Subscriber Network Application Policy
 ** Module   :   gr-manager
 ** Date: Apr 10, 2015               
 ** Author: Chen Zhenhua
 ** (C) Copyright 2015, Hewlett-Packard Company, All Rights Reserved.
 ** This software is the proprietary information of HP, Inc.  
 ** Use is subject to license terms.
 *****************************************************************
 ** Description:   
 **      While starting or stopping all session server, invoke the action handler to check session server status, 
 *  till the status return or timeout. 
 **    
 ****************************************************************/
package com.hp.snap.gr.action.impl;

import com.hp.snap.gr.exception.ActionException;
import com.hp.snap.gr.model.SessionServerStatus;
import com.hp.snap.gr.model.jaxb.ActionType;
import com.hp.snap.gr.model.jaxb.GeneralActionType;
import com.hp.snap.gr.model.jaxb.ParameterType;
import com.hp.snap.gr.utils.Constants;
import com.hp.snap.gr.utils.JSONUtils;
import com.hp.snap.gr.utils.SSHTools;
import com.hp.snap.gr.utils.Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.io.LineNumberReader;
import java.io.StringReader;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * 
 * While starting or stopping all session server, invoke the action handler to check the status, till the status return
 * or timeout. If timeout, the action will throw a ActionException.
 * 
 * <p>
 * There are three parameters should be configured: Shell, OperationType and Timeout. Shell: get session server status
 * shell script. OperationType: mark the operation is start or stop, optional value is: StartAll or StopAll Timeout:
 * check status timeout
 * 
 * <P>
 * Version: 3.3 <br>
 * Author: Chen Zhenhua Date: Apr 10, 2015
 * 
 * </P>
 * 
 **/
public class CheckSSStatusForSartAllORStopAllActionHandler extends
        AbstractActionHandler {

    private final static String SS_STATUS_RESULT_PREFIX = "{\"results\"";
    private final static String OP_START_ALL = "StartAll";
    private final static String OP_STOP_ALL = "StopAll";
    private static Logger logger = LoggerFactory.getLogger(CheckSSStatusForSartAllORStopAllActionHandler.class);

    @Override
    public void execute(ActionType action,
                        Map<String, Object> actionPlanInputs,
                        Map<String, Object> actionPlanOutputs) throws ActionException {


        GeneralActionType actionType = (GeneralActionType) action;
        List<ParameterType> parameterTypes = actionType.getParameter();
        Map<String, String> parameterMap = Utils.contructParamMap(parameterTypes);
        String shellscript = parameterMap.get("Shell");
        String opType = parameterMap.get("OperationType");
        int timeoutSeconds = (parameterMap.get("Timeout")==null || parameterMap.get("OperationType").isEmpty())?1:Integer.parseInt(parameterMap.get("Timeout"));

        String currentSiteName = Utils.getConfigurationValue(Constants.CFG_GRL_DEPLOY_NAME);
        String grIP = Utils.getGRHostIP(currentSiteName);
        String sshUser = Utils.getConfigurationValue(Constants.CFG_GRG_ROOT + "/" + currentSiteName, Constants.CFG_GRG_SITE_SSH_USER);
        String result;

        int counter = 0;
        while (counter < timeoutSeconds) {

            SSHTools ssh = new SSHTools(sshUser, Constants.SSH_PATH + File.separator + Constants.SSH_KEY_FILE);
            try {
                result = ssh.executeRemoteShell(false, shellscript, grIP);
            } catch (Exception e) {
                throw new ActionException("Connect current session server failed!", e.getCause());
            } finally {
                ssh.closeAll();
            }
            int status = ssh.getExitStatusOfCommandResult(result);
            String resultStr = ssh.getCommandOutput(result);
            if (status != 0) {
                logger.error("execute the getting session server status shell script failed!");
                throw new ActionException("execute the getting session server status shell script failed!");
            }
            String ssStatusStr = "";
            try {
                LineNumberReader r = new LineNumberReader(new StringReader(
                        resultStr));
                for (String line = r.readLine(); line != null; line = r.readLine()) {
                    if (line.startsWith(SS_STATUS_RESULT_PREFIX)) {
                        ssStatusStr = line;
                        //break;
                    }
                }
            } catch (IOException e) {
                throw new ActionException(
                        "handle the session server status result failed!",
                        e.getCause());
            }
            if (logger.isDebugEnabled()) {
                logger.debug("session server status json string is:{}", ssStatusStr);
            }
            Map<String, SessionServerStatus> ssStatusMap = JSONUtils.getSSStatus(ssStatusStr, false);
            Map<String, Integer> ssTypeStartCounter = Utils.getSSTypeCounter(ssStatusMap.keySet());
            Map<String, Integer> ssActiveCounterRule = Utils.getSSCounterForActive();

            boolean ssStatusIsOK = true;
            if (logger.isDebugEnabled()) {
                logger.debug("Check session server Status time:{}", new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Calendar.getInstance().getTime()));
            }
            if (OP_START_ALL.equals(opType)) {
                if (ssStatusMap.size() == 0) ssStatusIsOK = false;
                Iterator<Map.Entry<String, SessionServerStatus>> its = ssStatusMap.entrySet().iterator();
                while (its.hasNext()) {
                    Map.Entry<String, SessionServerStatus> entry = its.next();
                    SessionServerStatus ssStatus = entry.getValue();
                    if (logger.isDebugEnabled()) {
                        logger.debug("session server name: {}, State:{}, Status:{}", new Object[]{ssStatus.getName(), ssStatus.getProcessStatus(), ssStatus.getKernelStatus()});
                    }
                    if (SessionServerStatus.KernelStatus.ACTIVE == ssStatus.getKernelStatus()) {
                        String ssType = Utils.getSSType(ssStatus.getName());
                        ssTypeStartCounter.put(ssType, ssTypeStartCounter.get(ssType) + 1);
                    }
                }
                Utils.printSSTypeCounter(ssTypeStartCounter);
                for (String ssType : ssTypeStartCounter.keySet()) {
                    int checkCounter = ssActiveCounterRule.get(ssType) != null ? ssActiveCounterRule.get(ssType) : 0;
                    if (ssTypeStartCounter.get(ssType) < checkCounter)
                        ssStatusIsOK &= false;
                }
            } else if (OP_STOP_ALL.equals(opType)) {
                if (ssStatusMap.size() == 0) ssStatusIsOK = false;
                Iterator<Map.Entry<String, SessionServerStatus>> its = ssStatusMap.entrySet().iterator();
                while (its.hasNext()) {
                    Map.Entry<String, SessionServerStatus> entry = its.next();
                    SessionServerStatus ssStatus = entry.getValue();
                    if (logger.isDebugEnabled()) {
                        logger.debug("session server name: {}, State:{}, Status:{}", new Object[]{ssStatus.getName(), ssStatus.getProcessStatus(), ssStatus.getKernelStatus()});
                    }
                    if (SessionServerStatus.ProcessStatus.STOPPED != ssStatus.getProcessStatus())
                        ssStatusIsOK &= false;
                }
            }

            if (ssStatusIsOK)
                break;
            else {
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    logger.error(e.getMessage());
                }
                counter += 5;
                if (counter >= timeoutSeconds) {
                    if (OP_START_ALL.equals(opType)) {
                        Constants.CONSOLE.info("Started session servers number is lower than the number of configuation!");
                    }else if (OP_STOP_ALL.equals(opType)) {
                        Constants.CONSOLE.info("Stopped session server do not return correct status!");
                    }
                    throw new ActionException("the operation {" + opType + "} session server do not return correct status!!");
                }
            }

        }


    }

}
